home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / noodle / noodle.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  22.9 KB  |  645 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. //
  18. // Generalized Cylinder program
  19. //
  20.  
  21. #include <stdio.h>
  22. #include <getopt.h>
  23. #include <math.h>
  24. #include <malloc.h>
  25. #include <unistd.h>
  26.  
  27. #include <Inventor/SoPickedPoint.h>
  28. #include <Inventor/Xt/SoXt.h>
  29. #include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
  30. #include <Inventor/Xt/viewers/SoXtPlaneViewer.h>
  31. #include <Inventor/actions/SoBoxHighlightRenderAction.h>
  32. #include <Inventor/actions/SoSearchAction.h>
  33. #include <Inventor/actions/SoWriteAction.h>
  34. #include <Inventor/nodes/SoNode.h>
  35. #include <Inventor/nodes/SoSelection.h>
  36. #include <Inventor/nodes/SoShapeHints.h>
  37.  
  38. #include <Xm/Xm.h>
  39. #include <Xm/Text.h>
  40. #include <Xm/Form.h>
  41. #include <Xm/Frame.h>
  42. #include <Xm/ScrollBar.h>
  43. #include <Xm/PushBG.h>
  44. #include <Xm/Label.h>
  45. #include <Xm/LabelG.h>
  46. #include <Xm/ToggleBG.h>
  47. #include <Xm/ToggleB.h>
  48. #include <Xm/RowColumn.h>
  49.  
  50. #include "LineManip.h"
  51. #include "GeneralizedCylinder.h"
  52. #include "NoodleSlider.h"
  53. #include "Interface.h"
  54. #include "WorldInfo.h"
  55.  
  56. ////////////////////////////////////////////////////
  57. // Print the usage message
  58. //
  59. static void
  60. print_usage(const char *progname)
  61. {
  62.     fprintf(stderr, "Usage: %s [ -h][-bg r g b] [infiles]\n", progname);
  63.     fprintf(stderr,
  64.         "\t-h           Help (Print this message)\n"
  65.         "\t-bg rgb      Background color triple for main renderArea\n"
  66.         "\tinfiles      Inventor Files to read into Scene\n"
  67.         );
  68.     exit(0);
  69. }
  70.  
  71. ////////////////////////////////////////////////////
  72. // Parse the command line arguments
  73. //
  74. static void
  75. parse_args(int argc, char **argv, char *&in_filename, SbColor in_bgColor )
  76. {
  77.     int curArg = 1;
  78.     SbBool moreOpts = TRUE;
  79.  
  80.     while ( moreOpts && curArg < argc ) {
  81.     if ( !strcmp(argv[curArg], "-bg")) {
  82.         curArg++;
  83.         float r, g, b;
  84.         sscanf( argv[curArg++], "%f", &r );
  85.         sscanf( argv[curArg++], "%f", &g );
  86.         sscanf( argv[curArg++], "%f", &b );
  87.         in_bgColor.setValue( r, g, b );
  88.     }
  89.     else if ( !strcmp(argv[curArg], "-h")) {
  90.         print_usage(argv[0]);
  91.         exit(0);
  92.     }
  93.     else if ( !strncmp(argv[curArg], "-", 1)) {
  94.         print_usage(argv[0]);
  95.         exit(0);
  96.     }
  97.     else
  98.         moreOpts = FALSE;
  99.     }
  100.  
  101.     // Remaining argument should be fileName.
  102.     if (argc == curArg)
  103.     in_filename = NULL;
  104.     else
  105.     in_filename = strdup( argv[curArg] );
  106. }
  107.  
  108. //
  109. // These are defined in profile.c++
  110. //
  111. extern void clearProfilePoints();
  112. extern void clearCrossSectionPoints();
  113. extern void clearSpinePoints();
  114. extern void clearTwistPoints();
  115. extern void makeReverseSection();
  116. extern void makeCircularSection();
  117. extern void makeCircularSpine();
  118. extern void makeSemiCircularSpine();
  119.  
  120. Widget closeProfileButton;
  121. Widget closeSectionButton;
  122. Widget closeSpineButton;
  123. Widget closeTwistButton;
  124.  
  125. SoXtPlaneViewer *profilePlaneViewer;
  126. SoXtPlaneViewer *crossSectionPlaneViewer;
  127. SoXtExaminerViewer *spinePlaneViewer;
  128. SoXtPlaneViewer *twistPlaneViewer;
  129. SoXtExaminerViewer *examViewer;
  130.  
  131.  
  132. //
  133. // Callback for the close buttons
  134. //
  135. void
  136. closeProfileCallback(Widget w, XtPointer data, XtPointer)
  137. {
  138.     SbBool test = XmToggleButtonGetState( w );
  139.     Interface  *stuff = (Interface *) data;
  140.     GeneralizedCylinder *s = stuff->getWorldInfo()->getCurrentNoodle();
  141.     if ( s != NULL )
  142.     s->profileClosed = test;
  143.  
  144. }
  145. void
  146. closeSectionCallback(Widget w, XtPointer data, XtPointer)
  147. {
  148.     SbBool test = XmToggleButtonGetState( w );
  149.     Interface  *stuff = (Interface *) data;
  150.     GeneralizedCylinder *s = stuff->getWorldInfo()->getCurrentNoodle();
  151.     if ( s != NULL )
  152.     s->crossSectionClosed = test;
  153.  
  154. }
  155. void
  156. closeSpineCallback(Widget w, XtPointer data, XtPointer)
  157. {
  158.     SbBool test = XmToggleButtonGetState( w );
  159.     Interface  *stuff = (Interface *) data;
  160.     GeneralizedCylinder *s = stuff->getWorldInfo()->getCurrentNoodle();
  161.     if ( s != NULL )
  162.     s->spineClosed = test;
  163.  
  164. }
  165. void
  166. closeTwistCallback(Widget w, XtPointer data, XtPointer)
  167. {
  168.     SbBool test = XmToggleButtonGetState( w );
  169.     Interface  *stuff = (Interface *) data;
  170.     GeneralizedCylinder *s = stuff->getWorldInfo()->getCurrentNoodle();
  171.     if ( s != NULL )
  172.     s->twistClosed = test;
  173.  
  174. }
  175.  
  176. //
  177. // Callback for the clear buttons
  178. //
  179. void
  180. clearProfileCallback(Widget, XtPointer data, XtPointer)
  181. {
  182.     clearProfilePoints();
  183.  
  184.     // Also, set the curve to not be closed. It's really irritating
  185.     // to have to clear, then un-close the polygon. So do it automatically
  186.     // Note that, all we have to do is set the toggle. By passing the
  187.     // third argument as TRUE, the closeCallback gets called for us!
  188.     Widget closeToggle = (Widget) data;
  189.     XmToggleButtonSetState( closeToggle, FALSE, TRUE );
  190. }
  191.  
  192. void
  193. clearSectionCallback(Widget, XtPointer  data, XtPointer)
  194. {
  195.     clearCrossSectionPoints();
  196.  
  197.     // Also, set the curve to not be closed. It's really irritating
  198.     // to have to clear, then un-close the polygon. So do it automatically
  199.     // Note that, all we have to do is set the toggle. By passing the
  200.     // third argument as TRUE, the closeCallback gets called for us!
  201.     Widget closeToggle = (Widget) data;
  202.     XmToggleButtonSetState( closeToggle, FALSE, TRUE );
  203. }
  204.  
  205. void
  206. clearSpineCallback(Widget, XtPointer  data, XtPointer)
  207. {
  208.     clearSpinePoints();
  209.  
  210.     // Also, set the curve to not be closed. It's really irritating
  211.     // to have to clear, then un-close the polygon. So do it automatically
  212.     // Note that, all we have to do is set the toggle. By passing the
  213.     // third argument as TRUE, the closeCallback gets called for us!
  214.     Widget closeToggle = (Widget) data;
  215.     XmToggleButtonSetState( closeToggle, FALSE, TRUE );
  216. }
  217.  
  218. void
  219. reverseSectionCallback(Widget, XtPointer, XtPointer)
  220. {
  221.     makeReverseSection();
  222. }
  223.  
  224. void
  225. circularSectionCallback(Widget, XtPointer, XtPointer)
  226. {
  227.     makeCircularSection();
  228. }
  229.  
  230. void
  231. circularSpineCallback(Widget, XtPointer, XtPointer)
  232. {
  233.     makeCircularSpine();
  234. }
  235.  
  236. void
  237. semiCircularSpineCallback(Widget, XtPointer, XtPointer)
  238. {
  239.     makeSemiCircularSpine();
  240. }
  241.  
  242. void
  243. clearTwistCallback(Widget, XtPointer  data, XtPointer)
  244. {
  245.     clearTwistPoints();
  246.  
  247.     // Also, set the curve to not be closed. It's really irritating
  248.     // to have to clear, then un-close the polygon. So do it automatically
  249.     // Note that, all we have to do is set the toggle. By passing the
  250.     // third argument as TRUE, the closeCallback gets called for us!
  251.     Widget closeToggle = (Widget) data;
  252.     XmToggleButtonSetState( closeToggle, FALSE, TRUE );
  253. }
  254.  
  255.  
  256. main(int argc, char **argv)
  257. {
  258.     // Parse command line arguments. This may fill in the 
  259.     // background color and fileName if successful.
  260.     char    *in_filename = NULL;
  261.     SbColor in_bgColor(0,0,0);
  262.     parse_args(argc, argv, in_filename, in_bgColor );
  263.  
  264.     // Initialize Inventor
  265.     Widget mainWindow = SoXt::init(argv[0]);
  266.     if (mainWindow == NULL) exit(1);
  267.  
  268.     // Initialize special classes.
  269.     GeneralizedCylinder::initClass();
  270.     LineManip2::initClass();
  271.  
  272.     // Create an interface.  
  273.     Interface *interface = new Interface();
  274.  
  275.     // Create a structure to hold our scene and pass it to the interface.
  276.     WorldInfo *worldInfo = new WorldInfo;
  277.     interface->setWorldInfo( worldInfo );
  278.  
  279.     // Set the filename and background color for the interface.
  280.         worldInfo->setFileName( in_filename );
  281.     interface->setBackgroundColor( in_bgColor );
  282.  
  283.     // Read the scene into worldInfo, if it received a filename
  284.     // during parse_args. This will also set the current noodle to 
  285.     // be the first noodle in found in the scene.
  286.     interface->readScene(NULL, TRUE);
  287.  
  288.     // If the scene was empty, add a noodle to it.
  289.     GeneralizedCylinder *curNoodle = worldInfo->getCurrentNoodle();
  290.     if ( !curNoodle )
  291.         curNoodle = worldInfo->addNewNoodle();
  292.  
  293.     // Create the form that surrounds the five viewers and the pulldown
  294.     // menus.
  295.     Arg resources[20];
  296.     int n = 0;
  297.     XtSetArg(resources[n], "width", 1200); n++;
  298.     XtSetArg(resources[n], "height", 800); n++;
  299.     Widget form = XmCreateForm(mainWindow, "form", resources, n); n = 0;
  300.  
  301.     // Build the interface (pulldowns). Get back the topmost widget it creates.
  302.     Widget menuWidget = interface->build( form );
  303.  
  304. #define STRING(a) XmStringCreate(a,XmSTRING_DEFAULT_CHARSET)
  305.     
  306.     // And the five viewers (one to edit the cross section, one to
  307.     // edit the spine, one to edit the profile (scale of the cross section as
  308.     // it travels along the spine), one to edit the twist of the crsoss section,
  309.     // and one to view the shaded geometry)
  310.     
  311.  
  312.     //*************
  313.     // View of complete 3d model
  314.     //*************
  315.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  316.     XtSetArg(resources[n], XmNtopWidget, menuWidget); n++;
  317.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  318.     XtSetArg(resources[n], XmNleftPosition, 33); n++;
  319.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  320.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  321.     XtSetArg(resources[n], XmNbottomPosition, 45); n++;
  322.     Widget frame2 = XmCreateFrame(form, "renderAreaFrame", resources,
  323.                   n); n = 0;
  324.  
  325.     // Create the examiner viewer...
  326.     examViewer = new SoXtExaminerViewer(frame2, "noodleMainWindow");
  327.     examViewer->setBackgroundColor( interface->getBackgroundColor() );
  328.  
  329.     interface->setMainViewer( examViewer );
  330.  
  331.     // Set it as part of the callback data.
  332.     // Scene graph
  333.     examViewer->setSceneGraph( worldInfo->getWorldRoot() );
  334.     // Selection
  335.     examViewer->redrawOnSelectionChange( worldInfo->getSelectorNode() );
  336.     // Highlighting
  337.     SoBoxHighlightRenderAction *hlRA = new SoBoxHighlightRenderAction;
  338.     hlRA->setVisible(TRUE);
  339.     examViewer->setGLRenderAction(hlRA);
  340.  
  341.     // How it looks/works
  342.     examViewer->setBorder(FALSE);
  343.     examViewer->setAnimationEnabled(FALSE);
  344.     examViewer->show();
  345.     XtManageChild(frame2);
  346.     
  347.     //*************
  348.     // PROFILE VIEW
  349.     //*************
  350.     // Form containing viewer and controls
  351.     n = 0;
  352.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
  353.     XtSetArg(resources[n], XmNtopWidget, menuWidget); n++;
  354.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  355.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  356.     XtSetArg(resources[n], XmNrightPosition, 33); n++;
  357.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
  358.     XtSetArg(resources[n], XmNbottomPosition, 45); n++;
  359.     Widget form1 = XmCreateForm(form, "profileViewForm", resources,
  360.                   n); n = 0;
  361.  
  362.     // Row Column - goes along bottom edge of form, contains a button.
  363.     XtSetArg(resources[n], XmNorientation, XmHORIZONTAL); ++n;
  364.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  365.     XtSetArg(resources[n], XmNadjustLast, FALSE); ++n;
  366.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  367.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  368.     Widget rc1 = XmCreateRowColumn(form1, "profileStuff",
  369.                   resources, n); n = 0;
  370.     // Close profile button
  371.     XtSetArg(resources[n], XmNlabelString, STRING("Close Profile")); ++n;
  372.     closeProfileButton = XmCreateToggleButtonGadget(rc1, "closeProfile",
  373.                          resources, n); n = 0;
  374.     XmToggleButtonSetState( closeProfileButton, 
  375.                 curNoodle->profileClosed.getValue(), FALSE );
  376.     XtAddCallback(closeProfileButton, XmNvalueChangedCallback,
  377.           closeProfileCallback, (XtPointer)interface);
  378.     XtManageChild(closeProfileButton);
  379.     XtManageChild(rc1);
  380.  
  381.     // Clear profile button
  382.     XtSetArg(resources[n], XmNlabelString, STRING("Clear Profile")); ++n;
  383.     Widget clearProfileButton = XmCreatePushButtonGadget(rc1, "clearProfile",
  384.                          resources, n); n = 0;
  385.     XtAddCallback(clearProfileButton, XmNactivateCallback,
  386.           clearProfileCallback, (XtPointer)closeProfileButton);
  387.     XtManageChild(clearProfileButton);
  388.     XtManageChild(rc1);
  389.  
  390.     // Frame = top Section of Form
  391.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_FORM); n++;
  392.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  393.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  394.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  395.     XtSetArg(resources[n], XmNbottomWidget, rc1); n++;
  396.     Widget frame1 = XmCreateFrame(form1, "profileViewFrame", resources,
  397.                   n); n = 0;
  398.     // Put viewer in frame
  399.     profilePlaneViewer = new SoXtPlaneViewer(frame1);
  400.     profilePlaneViewer->setBorder(FALSE);
  401.     profilePlaneViewer->setDecoration(FALSE);
  402.     profilePlaneViewer->setViewing(FALSE);
  403.     profilePlaneViewer->show();
  404.     interface->setProfileViewer( profilePlaneViewer );
  405.     interface->setProfileCloseButton( closeProfileButton );
  406.     XtManageChild(frame1);
  407.  
  408.     XtManageChild(form1);
  409.  
  410.     //*************
  411.     // CROSS SECTION VIEW
  412.     //*************
  413.     // Form containing viewer and controls
  414.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  415.     XtSetArg(resources[n], XmNtopPosition, 45); n++;
  416.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  417.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  418.     XtSetArg(resources[n], XmNrightPosition, 33); n++;
  419.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  420.     Widget form3 = XmCreateForm(form, "crossSectionViewForm", resources,
  421.                   n); n = 0;
  422.  
  423.     // Row Column - goes along bottom edge of form, contains a button.
  424.     XtSetArg(resources[n], XmNorientation, XmHORIZONTAL); ++n;
  425.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  426.     XtSetArg(resources[n], XmNadjustLast, FALSE); ++n;
  427.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  428.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  429.     Widget rc3 = XmCreateRowColumn(form3, "crossSectionStuff",
  430.                   resources, n); n = 0;
  431.     // Close crossSection button
  432.     XtSetArg(resources[n], XmNlabelString, STRING("Close Section")); ++n;
  433.     closeSectionButton = XmCreateToggleButtonGadget(rc3, "closeSection",
  434.                          resources, n); n = 0;
  435.     XmToggleButtonSetState( closeSectionButton, 
  436.                 curNoodle->crossSectionClosed.getValue(), FALSE );
  437.     XtAddCallback(closeSectionButton, XmNvalueChangedCallback,
  438.           closeSectionCallback, (XtPointer)interface);
  439.     XtManageChild(closeSectionButton);
  440.     XtManageChild(rc3);
  441.  
  442.     // Clear crossSection button
  443.     XtSetArg(resources[n], XmNlabelString, STRING("Clear Section")); ++n;
  444.     Widget clearSectionButton = XmCreatePushButtonGadget(rc3, "clearSection",
  445.                          resources, n); n = 0;
  446.     XtAddCallback(clearSectionButton, XmNactivateCallback,
  447.           clearSectionCallback, (XtPointer)closeSectionButton);
  448.     XtManageChild(clearSectionButton);
  449.     XtManageChild(rc3);
  450.  
  451.     // circular section button
  452.     XtSetArg(resources[n], XmNlabelString, STRING("Circle")); ++n;
  453.     Widget circularSectionButton = XmCreatePushButtonGadget(rc3,"circle",
  454.                          resources, n); n = 0;
  455.     XtAddCallback(circularSectionButton, XmNactivateCallback,
  456.           circularSectionCallback, (XtPointer)circularSectionButton);
  457.     XtManageChild(circularSectionButton);
  458.     XtManageChild(rc3);
  459.  
  460.     // reverse section button
  461.     XtSetArg(resources[n], XmNlabelString, STRING("Reverse Order")); ++n;
  462.     Widget reverseSectionButton = XmCreatePushButtonGadget(rc3,"circle",
  463.                          resources, n); n = 0;
  464.     XtAddCallback(reverseSectionButton, XmNactivateCallback,
  465.           reverseSectionCallback, (XtPointer)reverseSectionButton);
  466.     XtManageChild(reverseSectionButton);
  467.     XtManageChild(rc3);
  468.  
  469.     // Frame = top Section of Form
  470.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_FORM); n++;
  471.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  472.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  473.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  474.     XtSetArg(resources[n], XmNbottomWidget, rc3); n++;
  475.     Widget frame3 = XmCreateFrame(form3, "crossSectionViewFrame", resources,
  476.                   n); n = 0;
  477.     // Put viewer in frame
  478.     crossSectionPlaneViewer = new SoXtPlaneViewer(frame3);
  479.     crossSectionPlaneViewer->setBorder(FALSE);
  480.     crossSectionPlaneViewer->setDecoration(FALSE);
  481.     crossSectionPlaneViewer->setViewing(FALSE);
  482.     crossSectionPlaneViewer->show();
  483.     interface->setSectionViewer( crossSectionPlaneViewer );
  484.     interface->setSectionCloseButton( closeSectionButton );
  485.     XtManageChild(frame3);
  486.  
  487.     XtManageChild(form3);
  488.  
  489.  
  490.     //*************
  491.     // SPINE VIEW
  492.     //*************
  493.     // Form containing viewer and controls
  494.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  495.     XtSetArg(resources[n], XmNtopPosition, 45); n++;
  496.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  497.     XtSetArg(resources[n], XmNleftPosition, 33); n++;
  498.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_POSITION); n++;
  499.     XtSetArg(resources[n], XmNrightPosition, 66); n++;
  500.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  501.     Widget form4 = XmCreateForm(form, "spineViewForm", resources,
  502.                   n); n = 0;
  503.  
  504.     // Row Column - goes along bottom edge of form, contains a button.
  505.     XtSetArg(resources[n], XmNorientation, XmHORIZONTAL); ++n;
  506.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  507.     XtSetArg(resources[n], XmNadjustLast, FALSE); ++n;
  508.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  509.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  510.     Widget rc4 = XmCreateRowColumn(form4, "spineStuff",
  511.                   resources, n); n = 0;
  512.     // Close spine button
  513.     XtSetArg(resources[n], XmNlabelString, STRING("Close Spine")); ++n;
  514.     closeSpineButton = XmCreateToggleButtonGadget(rc4, "closeSpine",
  515.                          resources, n); n = 0;
  516.     XmToggleButtonSetState( closeSpineButton, 
  517.                 curNoodle->spineClosed.getValue(), FALSE );
  518.     XtAddCallback(closeSpineButton, XmNvalueChangedCallback,
  519.           closeSpineCallback, (XtPointer)interface);
  520.     XtManageChild(closeSpineButton);
  521.     XtManageChild(rc4);
  522.  
  523.     // Clear spine button
  524.     XtSetArg(resources[n], XmNlabelString, STRING("Clear Spine")); ++n;
  525.     Widget clearSpineButton = XmCreatePushButtonGadget(rc4, "clearSpine",
  526.                          resources, n); n = 0;
  527.     XtAddCallback(clearSpineButton, XmNactivateCallback,
  528.           clearSpineCallback, (XtPointer)closeSpineButton);
  529.     XtManageChild(clearSpineButton);
  530.     XtManageChild(rc4);
  531.  
  532.     // circular spine button
  533.     XtSetArg(resources[n], XmNlabelString, STRING("Circle")); ++n;
  534.     Widget circularSpineButton = XmCreatePushButtonGadget(rc4,"circle",
  535.                          resources, n); n = 0;
  536.     XtAddCallback(circularSpineButton, XmNactivateCallback,
  537.           circularSpineCallback, (XtPointer)circularSpineButton);
  538.     XtManageChild(circularSpineButton);
  539.     XtManageChild(rc4);
  540.  
  541.     // Semi-circular spine button
  542.     XtSetArg(resources[n], XmNlabelString, STRING("Semi-circle")); ++n;
  543.     Widget semiCircularSpineButton = XmCreatePushButtonGadget(rc4, "semiCircle",
  544.                          resources, n); n = 0;
  545.     XtAddCallback(semiCircularSpineButton, XmNactivateCallback,
  546.          semiCircularSpineCallback, (XtPointer)semiCircularSpineButton);
  547.     XtManageChild(semiCircularSpineButton);
  548.     XtManageChild(rc4);
  549.  
  550.     // Frame = top Section of Form
  551.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_FORM); n++;
  552.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  553.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  554.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  555.     XtSetArg(resources[n], XmNbottomWidget, rc4); n++;
  556.     Widget frame4 = XmCreateFrame(form4, "spineViewFrame", resources,
  557.                   n); n = 0;
  558.     // Put viewer in frame
  559.     spinePlaneViewer = new SoXtExaminerViewer(frame4);
  560.     spinePlaneViewer->setBorder(FALSE);
  561.     spinePlaneViewer->setDecoration(FALSE);
  562.     spinePlaneViewer->setViewing(FALSE);
  563.     spinePlaneViewer->show();
  564.     interface->setSpineViewer( spinePlaneViewer );
  565.     interface->setSpineCloseButton( closeSpineButton );
  566.     XtManageChild(frame4);
  567.  
  568.     XtManageChild(form4);
  569.  
  570.     //*************
  571.     // TWIST VIEW
  572.     //*************
  573.     // Form containing viewer and controls
  574.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_POSITION); n++;
  575.     XtSetArg(resources[n], XmNtopPosition, 45); n++;
  576.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_POSITION); n++;
  577.     XtSetArg(resources[n], XmNleftPosition, 66); n++;
  578.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  579.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  580.     Widget form5 = XmCreateForm(form, "twistViewForm", resources,
  581.                   n); n = 0;
  582.  
  583.     // Row Column - goes along bottom edge of form, contains a button.
  584.     XtSetArg(resources[n], XmNorientation, XmHORIZONTAL); ++n;
  585.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  586.     XtSetArg(resources[n], XmNadjustLast, FALSE); ++n;
  587.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  588.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_FORM); n++;
  589.     Widget rc5 = XmCreateRowColumn(form5, "twistStuff",
  590.                   resources, n); n = 0;
  591.     // Close twist button
  592.     XtSetArg(resources[n], XmNlabelString, STRING("Close Twist")); ++n;
  593.     closeTwistButton = XmCreateToggleButtonGadget(rc5, "closeTwist",
  594.                          resources, n); n = 0;
  595.     XmToggleButtonSetState( closeTwistButton, 
  596.                 curNoodle->twistClosed.getValue(), FALSE );
  597.     XtAddCallback(closeTwistButton, XmNvalueChangedCallback,
  598.           closeTwistCallback, (XtPointer)interface);
  599.     XtManageChild(closeTwistButton);
  600.     XtManageChild(rc5);
  601.  
  602.     // Clear Twist button
  603.     XtSetArg(resources[n], XmNlabelString, STRING("Clear Twist")); ++n;
  604.     Widget clearTwistButton = XmCreatePushButtonGadget(rc5, "clearTwist",
  605.                          resources, n); n = 0;
  606.     XtAddCallback(clearTwistButton, XmNactivateCallback,
  607.           clearTwistCallback, (XtPointer)closeTwistButton);
  608.     XtManageChild(clearTwistButton);
  609.     XtManageChild(rc5);
  610.  
  611.     // Frame = top Section of Form
  612.     XtSetArg(resources[n], XmNtopAttachment, XmATTACH_FORM); n++;
  613.     XtSetArg(resources[n], XmNleftAttachment, XmATTACH_FORM); n++;
  614.     XtSetArg(resources[n], XmNrightAttachment, XmATTACH_FORM); n++;
  615.     XtSetArg(resources[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
  616.     XtSetArg(resources[n], XmNbottomWidget, rc5); n++;
  617.     Widget frame5 = XmCreateFrame(form5, "twistViewFrame", resources,
  618.                   n); n = 0;
  619.     // Put viewer in frame
  620.     twistPlaneViewer = new SoXtPlaneViewer(frame5);
  621.     twistPlaneViewer->setBorder(FALSE);
  622.     twistPlaneViewer->setDecoration(FALSE);
  623.     twistPlaneViewer->setViewing(FALSE);
  624.     twistPlaneViewer->show();
  625.     interface->setTwistViewer( twistPlaneViewer );
  626.     interface->setTwistCloseButton( closeTwistButton );
  627.     XtManageChild(frame5);
  628.  
  629.     XtManageChild(form5);
  630.  
  631.     XtManageChild(form);
  632.  
  633.     examViewer->viewAll();
  634.  
  635.     // Tell the interface to display info about the current noodle
  636.     // This includes parameters in the pulldowns and also info in the
  637.     // graph viewers.
  638.     interface->setPrimarySelection( curNoodle );
  639.     
  640.     SoXt::show(mainWindow);
  641.  
  642.     SoXt::mainLoop();
  643. }
  644.  
  645.